package com.wkh.datastructure.blockingqueue;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
//单锁实现阻塞队列
public class BlockingQueue1<E> implements BlockingQueue<E> {
    private E[] array;
    private int head;
    private int tail;
    private int size;

    public BlockingQueue1(int capacity) {
        array = (E[]) new Object[capacity];
    }

    //锁对象
    private ReentrantLock lock = new ReentrantLock();
    //条件变量对象
    private Condition headWaits = lock.newCondition();//与poll方法有关
    private Condition tailWaits = lock.newCondition();//与offer方法有关

    @Override
    public void offer(E value) {
        //开锁
        try {
            lock.lockInterruptibly();
            while (isFull()) {//防止虚假唤醒
                tailWaits.await();
            }
            array[tail] = value;
            tail++;
            if (tail == array.length) {
                tail = 0;
            }
            size++;
            headWaits.signal();//唤醒等待非空的线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //解锁
            lock.unlock();
        }
    }

    @Override
    public boolean offer(E value, long timeout) throws InterruptedException {

            //开锁
            lock.lockInterruptibly();
        try {
            long t = TimeUnit.MILLISECONDS.toNanos(timeout);

            while (isFull()) {//防止虚假唤醒
                if (t<=0){
                    return false;
                }
                t = tailWaits.awaitNanos(t);
            }
            array[tail] = value;
            tail++;
            if (tail == array.length) {
                tail = 0;
            }
            size++;
            headWaits.signal();//唤醒等待非空的线程
            return true;
        } finally {
            //解锁
            lock.unlock();
        }

    }

    @Override
    public E poll() throws InterruptedException {
            lock.lockInterruptibly();
        try {
            //防止虚假唤醒
            while (isEmpty()) {
                headWaits.await();
            }
            E e = array[head];
            array[head] = null;
            head++;
            if (head == array.length) {
                head = 0;
            }
            size--;
            tailWaits.signal();
            return e;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }

    @Override
    public String toString() {
        return "BlockingQueue1{" +
                "array=" + Arrays.toString(array) + '}';
    }
}
